package com.dy.design_pattern_study.singleton_pattern.dome2;

import com.dy.design_pattern_study.singleton_pattern.dome1.Singleton;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @CreateBy zhangdingyi
 * @Date 2023-04-17
 * @Content 多线程单例模式 -懒汉式
 * 这个就是需要的时候得自个创建，因此在第一次访问的时候，可能因为多线程产生多个实例问题
 * 因此这里需要加锁限制
 */
public class MultiThreadSingleton {
    private static MultiThreadSingleton instance;

    //互斥锁
    private static volatile Boolean isLock = Boolean.FALSE;

    //获取锁计数
    private static volatile Integer lockNum = 0;

    //1.不能让外部创建对象的实例
    private MultiThreadSingleton() {
    }

    //2.获取互斥锁 ---这个互斥锁的方式不行 --直接用人家的Lock还多好
    public synchronized static Boolean tryLock() {
        if (lockNum == 1){
            return Boolean.FALSE;
        }

        //如果 锁已经被获取，就直接返回
        if (isLock == Boolean.TRUE) {
            //返回false 说明该锁已经被占用
            return Boolean.FALSE;
        } else {
            //获取锁成功！
            isLock = Boolean.TRUE;
            lockNum++;
        }
        return isLock;
    }

    //3.这里直接在方法加一个锁，一次仅能访问一个
    public static MultiThreadSingleton getInstance() {
        /*
            这里使用到双重锁定
            如果已有实例，则不能创建新的实例
            如果没有实例，仅能一个线程访问
            -----
            实例未被创建的时候再加锁处理。同时也能保证多线程的安全。
            这种做法被称为Double-Check Locking（双重锁定）
         */

        //如果已经有实例，则直接返回
        if (instance != null) {
            return instance;
        }

        //如果获取锁成功，才能进行访问 --这里直接加了类就可以了，后面需要学习一下synchronized MultiThreadSingleton.class
        synchronized (MultiThreadSingleton.class) {
            //只能由自身对实例进行创建
            //先判断实例是否被创建
            if (instance == null) {
                //如果没有就进行创建
                instance = new MultiThreadSingleton();
            }
            isLock = Boolean.FALSE;
        }

        //最后把实例进行返回
        return instance;
    }


}
